////////////////////////////////////////////////////////////
//Test SL031
//MCS51 source code
////////////////////////////////////////////////////////////   
#include <reg52.h>
#include <string.h>
#include <intrins.h>
#include <stdio.h>

#define  true     1
#define  false    0

#define  OSC_FREQ        22118400L
#define  TIME0_10ms      65536L - OSC_FREQ/1200L

#define  BOUND4800       256 - 24
#define  BOUND9600       256 - 12
#define  BOUND14400      256 - 8
#define  BOUND19200      256 - 6
#define  BOUND28800      256 - 4
#define  BOUND38400      256 - 3
#define  BOUND57600      256 - 2
#define  BOUND115200     256 - 1

#define SomeNOP(); _nop_();_nop_();_nop_();_nop_();

//IO definition
sbit CARDIN = P1^0;
sbit WAKEUP = P1^1;   
sbit OKLED  = P2^0;
sbit ERRLED = P2^1;
                                     

void InitializeSystem();                                                           
void SendCom(unsigned char *g_cCommand);                                           
void StartTime(unsigned int _MS);                                                  
void StopTime();
char ReadWriteUltralight(void);
char ReadWriteMifareStd(void);

//Command List, preamble + length + command code + data frame
unsigned char code SelectCard[3] =      {0xBA,0x02,0x01 };       
unsigned char code LoginSector0[11] =   {0xBA,0x0A,0x02,0x00,0xAA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};  
unsigned char code LoginSector1[11] =   {0xBA,0x0A,0x02,0x01,0xAA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
unsigned char code ReadBlock1[4]   =    {0xBA,0x03,0x03,0x01};                                     
unsigned char code WriteBlock1[20] =    {0xBA,0x13,0x04,0x01,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};                                
unsigned char code ReadValue[4]  =      {0xBA,0x03,0x05,0x04};  
unsigned char code WriteValue[8]  =     {0xBA,0x07,0x06,0x04,0x00,0x00,0x00,0x01};                                
unsigned char code IncrementValue[8] =  {0xBA,0x07,0x08,0x04,0x00,0x00,0x00,0x20};                                
unsigned char code DecrementValue[8] =  {0xBA,0x07,0x09,0x04,0x03,0x00,0x00,0x00};                                          
unsigned char code CopyValue[5] =       {0xBA,0x04,0x0A,0x04,0x05};
unsigned char code ReadULPage5[4] =     {0xBA,0x03,0x10,0x05};                                          
unsigned char code WriteULPage5[8] =    {0xBA,0x07,0x11,0x05,0x11,0x22,0x33,0x44};
unsigned char code Halt[4] =            {0xBA,0x03,0x50,0x00};             
                           
unsigned char g_ucReceBuf[21];                                      
unsigned char g_ucReceNum;                                          
unsigned char g_ucWatchTime; 
unsigned char g_ucCardType;
char g_cStatus;                                       
char g_cErr;

bit   g_bReceOver;                                                 
bit   g_bReceReady;
bit   g_bTimeOut;                                                  

void main() 
{
     InitializeSystem();	
     
     while(1)
     {

         while (!CARDIN)
         {
              g_cErr = 0;

//Get the unique serial number of Mifare Card 
              SendCom(SelectCard);                              //
              StartTime(8);                                     //waitting until receive response from SL31 or over 80ms
              while (!g_bReceOver && !g_bTimeOut);              //
              StopTime();                                       //
              if ((g_ucReceBuf[2]!=0x01) || (g_ucReceBuf[3]!=0) || g_bTimeOut)
              {   continue;   }     


              if (g_ucReceBuf[1] == 8)
    	      {
    	          g_ucCardType = g_ucReceBuf[8];
    	      }
    	      else
    	      {
    	          g_ucCardType = g_ucReceBuf[11];
    	      }
    	      
    	      switch(g_ucCardType)
              {  
                  case 1://Mifare_Std_1K
                      g_cStatus = ReadWriteMifareStd( );
                      if (g_cStatus != true)
                      {    g_cErr = 3;    }
                      break;
                  case 2://Mifare_Pro 
                      g_cErr = 4;
                      break;
                  case 3://Mifare_UltraLight
                      g_cStatus = ReadWriteUltralight( );
                      if (g_cStatus != true)
                      {    g_cErr = 3;    }
                      break;
                  case 4://Mifare_Std_4K
                      g_cStatus = ReadWriteMifareStd( );
                      if (g_cStatus != true)
                      {    g_cErr = 3;    }
                      break;
                  case 5://Mifare_ProX 
                      g_cErr = 4;
                      break;
                  case 6://Mifare_DesFire 
                      g_cErr = 4;
                      break;                 
    	          default:
    	              g_cErr = 3;
                      break;
              }

          
              if (g_cErr == 0)
              {    
                  SendCom(Halt);                
                  StartTime(40);
                  while (!g_bTimeOut);
                  OKLED = 0;
               	  StartTime(10);
               	  while (!g_bTimeOut);
               	  StopTime();
                  WAKEUP = 0;
                  SomeNOP();
                  WAKEUP = 1;  
                  StartTime(10);
               	  while (!g_bTimeOut);
               	  StopTime(); 
               	  OKLED = 1; 
              }
              else
              {   
                  ERRLED = 0;
               	  StartTime(10);
               	  while (!g_bTimeOut);
               	  StopTime();
               	  ERRLED = 1; 
              } 
         }
    }
}


////////////////////////////////////////////////////////////
char ReadWriteUltralight(void)
{
	
//Write data to page5 of UltraLight    
    SendCom(WriteULPage5);                     
    StartTime(8);                                     
    while (!g_bReceOver && !g_bTimeOut);              
    StopTime();                                       
    if ((g_ucReceBuf[2]!=0x11) || (g_ucReceBuf[3]!=0) || g_bTimeOut)
    {    return false;   }

//read data from page5 of UltraLight             
    SendCom(ReadULPage5);                     
    StartTime(8);                                     
    while (!g_bReceOver && !g_bTimeOut);              
    StopTime();                                       
    if ((g_ucReceBuf[2]!=0x10) || (g_ucReceBuf[3]!=0) || g_bTimeOut)
    {    return false;   }                                            

//Compare read data with written data        
    if (memcmp(&WriteULPage5[4], &g_ucReceBuf[4], 4) != 0 )
    {    return false;   }
    else
    {    return true;   }        
}

////////////////////////////////////////////////////////////
char ReadWriteMifareStd(void)
{
    long lPurseValue;

//Verify password of sector0   
    SendCom(LoginSector0);                
    StartTime(8);
    while (!g_bReceOver && !g_bTimeOut);
    StopTime();
    if ((g_ucReceBuf[2]!=0x02) || (g_ucReceBuf[3]!=2) || g_bTimeOut)
    {    return false;   }               
             
//Write data to block1            
    SendCom(WriteBlock1);                 
    StartTime(8);
    while (!g_bReceOver && !g_bTimeOut);
    StopTime();
    if ((g_ucReceBuf[2]!=0x04) || (g_ucReceBuf[3]!=0) || g_bTimeOut)
    {    return false;   }
    if (memcmp(&WriteBlock1[4], &g_ucReceBuf[4], 16) != 0)
    {    return false;   }                 
             
//Read data from block1             
    SendCom(ReadBlock1);                 
    StartTime(8);
    while (!g_bReceOver && !g_bTimeOut);
    StopTime();
    if ((g_ucReceBuf[2]!=0x03) ||(g_ucReceBuf[3]!=0) || g_bTimeOut)
    {    return false;   }

//Compare read data with written data      
    if (memcmp(&WriteBlock1[4], &g_ucReceBuf[4], 16) != 0)
    {    return false;   }                   

//Verify password of sector1 
    SendCom(LoginSector1);                
    StartTime(8);
    while (!g_bReceOver && !g_bTimeOut);
    StopTime();
    if ((g_ucReceBuf[2]!=0x02) || (g_ucReceBuf[3]!=2) || g_bTimeOut)
    {    return false;   }  
                          
//Initialize block4 to one purse, and value = 0x01000000             
    SendCom(WriteValue);                 
    StartTime(8);
    while (!g_bReceOver && !g_bTimeOut);
    StopTime();
    if ((g_ucReceBuf[2]!=0x06) || (g_ucReceBuf[3]!=0) || g_bTimeOut)
    {    return false;   } 
    if (memcmp(&WriteValue[4], &g_ucReceBuf[4], 4) != 0)
    {    return false;   }     

//Increment            
    SendCom(IncrementValue);                 
    StartTime(8);
    while (!g_bReceOver && !g_bTimeOut);
    StopTime();
    if ((g_ucReceBuf[2]!=0x08) || (g_ucReceBuf[3]!=0) || g_bTimeOut)
    {    return false;   }  

//Decrement            
    SendCom(DecrementValue);                 
    StartTime(8);
    while (!g_bReceOver && !g_bTimeOut);
    StopTime();
    if ((g_ucReceBuf[2]!=0x09) || (g_ucReceBuf[3]!=0) || g_bTimeOut)
    {    return false;   }    
             
//Backup purse to blcok5           
    SendCom(CopyValue);                 
    StartTime(8);
    while (!g_bReceOver && !g_bTimeOut);
    StopTime();
    if ((g_ucReceBuf[2]!=0x0A) || (g_ucReceBuf[3]!=0) || g_bTimeOut)
    {    return false;   }                           
                           
//Read purse value from blcok5             
    SendCom(ReadValue);                
    StartTime(8);
    while (!g_bReceOver && !g_bTimeOut);
    StopTime();
    if ((g_ucReceBuf[2]!=0x05) || (g_ucReceBuf[3]!=0) || g_bTimeOut)
    {    return false;   }
    
//Check value    
    lPurseValue = g_ucReceBuf[7]*0x1000000 + g_ucReceBuf[6]*0x10000 + g_ucReceBuf[5]*0x100 + g_ucReceBuf[4];
    if (lPurseValue != 0x01000000 + 0x20000000 - 0x00000003)
    {    return false;   }
    else
    {    return true;   } 

}
        
////////////////////////////////////////////////////////////
void InitializeSystem()
{
    TMOD &= 0x0F; 
    TMOD |= 0x21; 
    PCON |= 0x80;
    SCON  = 0x50; 
    TH1 = TL1 = BOUND115200; 
    g_ucReceNum = 0;
    g_bReceOver = 0;
    g_bReceReady = 0;
    TR1   = 1;
    IE   |= 0x90;
}

////////////////////////////////////////////////////////////
void StartTime(unsigned int _MS)
{
    TH0 = (unsigned char)((TIME0_10ms>>8)&0xFF);
    TL0 = (unsigned char)(TIME0_10ms&0xFF);
    g_ucWatchTime = _MS;
    g_bTimeOut = 0;
    ET0 = 1;
    TR0 = 1;
}	

////////////////////////////////////////////////////////////
time0_int () interrupt 1 using 1
{
    TH0 = (unsigned char)((TIME0_10ms>>8) & 0xFF);
    TL0 = (unsigned char)(TIME0_10ms & 0xFF);
    if (g_ucWatchTime--==0)
    {    g_bTimeOut = 1;    }
}

////////////////////////////////////////////////////////////
void StopTime()
{
    ET0 = 0;
    TR0 = 0;
}	

////////////////////////////////////////////////////////////
//Send command to SL031
////////////////////////////////////////////////////////////
void SendCom(unsigned char *g_cCommand)
{    
     unsigned char i,chkdata,sendleg;

     ES = 0;
     sendleg = *(g_cCommand+1) + 1;
     
     chkdata = 0;
     for(i=0; i<sendleg; i++)
     {    
     	  chkdata ^= *(g_cCommand+i);
     	  
     	  TI = 0;
     	  SBUF = *(g_cCommand+i);
     	  while(!TI);
     }
     
     TI = 0;
     SBUF = chkdata;
     while (!TI);
     TI = 0;
     
     g_bReceReady = 1;
     g_bReceOver = 0;
     ES = 1;
}

/////////////////////////////////////////////////////////////////////
//Get result from SL031
/////////////////////////////////////////////////////////////////////
seri_int () interrupt 4 using 1
{
   unsigned char i,j;
   unsigned char rece_data = SBUF;
   unsigned char verify = 0;
   
   if(RI)
   {    
       RI = 0;
       if (g_bReceReady)
       {  
           switch (rece_data)
           {    
               case 0xBD:
                    g_bReceReady = 0;
                    g_bReceOver = 0;
                    g_ucReceNum = 0;
                    g_ucReceBuf[0] = 0xBD;
                    g_ucReceBuf[1] = 0;
                    break;
               default:
                    g_ucReceNum++;
                    break;
           }
       }
       else
       {    
           i = ++g_ucReceNum;
           g_ucReceBuf[i] = rece_data;
	   if (g_ucReceBuf[1] == g_ucReceNum - 1)
	   {
	       for (j=0; j<g_ucReceNum+1; j++)
               {   verify ^= g_ucReceBuf[j];    }
               g_bReceOver = 1;
               ES = 0;
           }
           if (g_ucReceNum > sizeof(g_ucReceBuf))
           {
               g_bReceOver = 0;
               g_ucReceNum = 0;
           }
        }
    }
    
    if(TI)
    {   
        TI = 0; 
    }
}
